/*************************************************************************
@Author: bighu
@Created Time : 2022年01月14日 星期五 20时58分37秒
@File Name: icmp.go
@Description:
************************************************************************/
package main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	serveice := os.Args[1]
	netcon, _ := net.Dial("ip4:icmp", serveice)
	go sendIcmp(os.Args, netcon)
	getIcmp(netcon)

}

//监听icmp
func getIcmp(conn net.Conn) {
	//自动关闭连接
	defer conn.Close()
	for {
		msg := make([]byte, 512)
		_, err := conn.Read(msg)
		getError(err)
		if err == nil {
			fmt.Println("ping成功")
			fmt.Println(msg)
			break
		}
	}
}

//发送一个icmp请求
func sendIcmp(args []string, netcon net.Conn) {
	if len(args) != 2 {
		fmt.Println("Usage:", args[0], "host")
		os.Exit(1)
	}
	var msg [512]byte
	msg[0] = 8 //echo
	msg[1] = 0 //code 0
	msg[2] = 0 //checksum
	msg[3] = 0 //checksum
	msg[4] = 0
	msg[5] = 6
	msg[6] = 0
	msg[7] = 1
	len := 8
	check := checksum(msg[0:len])
	msg[2] = byte(check >> 8)
	msg[3] = byte(check & 255)
	_, err := netcon.Write(msg[0:len])
	getError(err)
}

func getError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error:%s", err.Error())
	}
}

//j计算校验合
func checksum(msg []byte) uint16 {
	//存放合病后的两个2byte的值
	var TwoByteData1 uint16 = 0
	var TwoByteData2 uint16 = 0
	//将两个byte合并为一个uint16
	TwoByteData1 = (uint16)(msg[0])<<8 + (uint16)(msg[1])
	for i := 0; i < (int)((len(msg))/2)-1; i++ {

		TwoByteData2 = (uint16)(msg[2*(i+1)])<<8 + (uint16)(msg[2*(i+1)+1])
		//如果溢出则在最前面+1
		if TwoByteData2 > 0xffff-TwoByteData1 {
			TwoByteData1 = TwoByteData1 ^ TwoByteData2 + 1
		} else {
			TwoByteData1 = TwoByteData1 ^ TwoByteData2

		}
	}

	return ^TwoByteData1
}
